package la.iok.hzsvn.lewin.movie.service;

import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.entity.MovieScene;
import la.iok.hzsvn.lewin.movie.mapper.MovieSceneMapper;
import la.iok.hzsvn.lewin.movie.model.DigestInfo;
import la.iok.hzsvn.lewin.movie.model.MovieSceneParam;
import la.iok.hzsvn.lewin.movie.model.MovieSceneVo;
import la.iok.hzsvn.lewin.movie.model.ObsSignedUrl;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.NotNullElement;
import la.iok.hzsvn.share.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class MovieSceneServiceImpl extends BaseServiceImpl<MovieScene, MovieSceneMapper,Long> implements MovieSceneService {
    private final MovieService movieService;
    private final MovieSceneFileService movieSceneFileService;

    public MovieSceneServiceImpl(MovieSceneMapper mapper, MovieService movieService,
                                 MovieSceneFileService movieSceneFileService) {
        super(mapper);
        this.movieService = movieService;
        this.movieSceneFileService = movieSceneFileService;
    }

    @NotNull
    @Override
    public Long save(@NotNull Token token, @NotNull Long movieId, @NotNull MovieSceneParam param) {
        movieService.validate(token,movieId);
        param.setName(ErrorCode.NAME_BLANK_ERROR.assertNotBlank(param.getName()));
        ErrorCode.PROPERTY_CHECK_ERROR.assertAnyOf(param.getPlayMode(),MovieScene.playModes,"播放模式","请选择正确的播放模式");
        MovieScene entity = new MovieScene();
        BeanUtils.copyProperties(param,entity);
        entity.setMovieId(movieId);
        insertSelective(entity);
        return entity.getId();
    }

    @Transactional
    @Override
    public void uploadFile(Token token, Long id, MultipartFile file) {
        MovieScene movieScene = validate(token,id);
        Long sceneFileId = movieSceneFileService.uploadFile(file);
        movieSceneFileService.decrement(movieScene.getFileId());
        update(id,"fileId",sceneFileId);
        movieSceneFileService.increment(sceneFileId);
    }

    @Override
    public ObsSignedUrl uploadFile(@NotNull Token token, @NotNull Long id, @NotNull DigestInfo digest) {
        MovieScene movieScene = validate(token,id);
        ObsSignedUrl url = movieSceneFileService.uploadFile(digest);
        movieSceneFileService.decrement(movieScene.getFileId());
        update(id,"fileId",url.getFileId());
        movieSceneFileService.increment(url.getFileId());
        url.setFileId(null);
        return url;
    }

    @Nullable
    @Override
    public String digest(@Nullable Long id) {
        MovieScene scene = select(id);
        ErrorCode.SCENE_NOT_EXIST.assertNotNull(scene,id);
        return movieSceneFileService.digest(scene.getFileId());
    }

    @Nullable
    @Override
    public String storePath(@Nullable Long id) {
        MovieScene scene = select(id);
        ErrorCode.SCENE_NOT_EXIST.assertNotNull(scene,id);
        return movieSceneFileService.storePath(scene.getFileId());
    }

    @Override
    public void update(@NotNull Token token, @NotNull Long id, @NotNull MovieSceneParam param){
        MovieScene scene = validate(token,id);
        BeanUtils.copyProperties(param,scene);
        mapper.updateSelective(scene);
    }

    @Transactional
    @Override
    public void delete(@NotNull Token token, @Nullable Long id) {
        MovieScene scene = validate(token,id);
        movieSceneFileService.decrement(scene.getFileId());
        delete(id);
    }

    @NotNull
    @NotNullElement
    @Override
    public List<MovieSceneVo> movieScenes(@NotNull Token token, @NotNull Long movieId) {
        movieService.validate(token,movieId);
        List<MovieScene> list = movieScenes(movieId);
        list.sort((item1, item2) -> {
            if (item1 == null && item2 == null) {
                return 0;
            }
            if (item1 == null) {
                return -1;
            }
            if (item2 == null) {
                return 1;
            }
            Integer s1 = item1.getSequence();
            Integer s2 = item2.getSequence();
            if (s1 == null && s2 == null) {
                return 0;
            }
            if (s1 == null) {
                return -1;
            }
            if (s2 == null) {
                return 1;
            }
            return s1.compareTo(s2);
        });
        return po2vo(list);
    }

    @NotNull
    @NotNullElement
    @Override
    public List<MovieScene> movieScenes(@Nullable Long movieId) {
        if(movieId == null){
            return Collections.emptyList();
        }
        return listByProperty("movieId",movieId);
    }

    private List<MovieSceneVo> po2vo(@NotNull @NotNullElement List<MovieScene> list){
        return list.stream().map(item->{
            MovieSceneVo vo = new MovieSceneVo();
            BeanUtils.copyProperties(item,vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @NotNull
    @Override
    public MovieScene validate(@NotNull Token token, @NotNull Long id){
        MovieScene scene = select(id);
        ErrorCode.SCENE_NOT_EXIST.assertNotNull(scene,id);
        movieService.validate(token,scene.getMovieId());
        return scene;
    }

    @Override
    public void downloadFile(@NotNull Token token, @NotNull HttpServletResponse response, @NotNull Long id) {
        MovieScene scene = validate(token,id);
        movieSceneFileService.downloadFile(response,scene.getFileId(), scene.getName());
    }

    @Override
    public ObsSignedUrl obsGet(@NotNull Token token, Long id) {
        MovieScene scene = validate(token,id);
        return movieSceneFileService.obsGet(scene.getFileId());
    }
}
